package tx.os3.opdracht1.deel2;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

@SuppressWarnings("serial")
public class MainWindow extends JFrame implements Observer {

    // Layout
    private static final int WIDTH = 500;
    private static final int HEIGHT = 500;
    private GroupLayout layout;
    private JPanel panel;

    // Buttons
    private JButton openDirButton;
    private final String openDirButtonText = "Kies een map";
    private JButton parentDirButton;
    private final String parentDirButtonText = "\u21B0";
    private Icon loadingIcon;

    // Labels
    private JLabel loadingLabel;
    private JLabel currentPathLabel;

    // Info panel
    private JPanel infoPanel;
    private JLabel infoFileName;
    private JLabel infoFileSize;
    private JLabel infoDateModified;

    // List component
    private JScrollPane scrollPane;
    private JList fileList;

    // File chooser
    private final JFileChooser fileChooser = new JFileChooser();

    // FileLister model
    private FileLister fileLister;

    public MainWindow() {
        this.panel = new JPanel();
        this.layout = new GroupLayout(this.panel);
        this.openDirButton = new JButton(this.openDirButtonText);
        this.parentDirButton = new JButton(this.parentDirButtonText);
        this.currentPathLabel = new JLabel();
        this.fileList = new JList();
        this.infoPanel = new JPanel();
        this.infoFileName = new JLabel();
        this.infoFileSize = new JLabel();
        this.infoDateModified = new JLabel();
        this.scrollPane = new JScrollPane();

        try {
            this.loadingIcon = new ImageIcon(
                    new URL(
                            "http://www.gmund.com/skin/frontend/base/default/images/opc-ajax-loader.gif"));
        }
        catch(MalformedURLException e) {
            Logger.getAnonymousLogger().log(Level.WARNING, e.getMessage());
        }

        this.loadingLabel = new JLabel(this.loadingIcon);

        this.prepareLayoutComponents();
        this.layoutComponents();
    }

    private void prepareLayoutComponents() {
        this.openDirButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int returnVal = fileChooser.showOpenDialog(MainWindow.this);

                if(returnVal == JFileChooser.APPROVE_OPTION) {
                    fileLister.setCurrentDir(fileChooser.getSelectedFile());
                    loadingLabel.setVisible(true);
                }
            }
        });

        this.parentDirButton.setEnabled(false);
        this.parentDirButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(fileLister.getCurrentDir() != null
                        && fileLister.getCurrentDir().getParentFile() != null) {
                    fileLister.setCurrentDir(fileLister.getCurrentDir()
                            .getParentFile());
                    loadingLabel.setVisible(true);
                }
            }
        });

        this.fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

        // Add a listener for mouse clicks
        this.fileList.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent evt) {
                File selectedFile = (File) fileList.getSelectedValue();
                if(selectedFile != null) {
                    infoFileName.setText(selectedFile.getName());
                    infoFileSize.setText("File size: "
                            + selectedFile.getTotalSpace() / 1024 + " KB");

                    infoDateModified.setText("Date modified: "
                            + new Date(selectedFile.lastModified()));

                    // Handle double click
                    if(evt.getClickCount() == 2) { // Double-click
                        if(selectedFile.isDirectory()) {
                            fileLister.setCurrentDir(selectedFile);
                        }
                    }
                }
            }
        });
    }

    private void layoutComponents() {
        // Window size
        this.setMinimumSize(new Dimension(WIDTH, HEIGHT));
        this.setResizable(true);

        this.add(this.panel);

        // Scrollpane for file list
        this.scrollPane.getViewport().add(this.fileList);

        // Create info panel
        this.infoPanel.setPreferredSize(new Dimension((int) this.infoPanel
                .getSize().getWidth(), 50));
        BoxLayout infoPanelLayout = new BoxLayout(this.infoPanel,
                BoxLayout.Y_AXIS);
        this.infoPanel.setLayout(infoPanelLayout);
        this.infoPanel.add(this.infoFileName);
        this.infoPanel.add(this.infoFileSize);
        this.infoPanel.add(this.infoDateModified);

        this.loadingLabel.setVisible(false);

        // Layout components
        this.panel.setLayout(this.layout);
        this.layout.setHorizontalGroup(this.layout
                .createParallelGroup()
                .addComponent(this.openDirButton, 0, GroupLayout.DEFAULT_SIZE,
                        Short.MAX_VALUE)
                .addGroup(
                        this.layout.createSequentialGroup()
                                .addComponent(this.parentDirButton)
                                .addComponent(this.loadingLabel)
                                .addComponent(this.currentPathLabel))
                .addComponent(this.scrollPane, 0, GroupLayout.DEFAULT_SIZE,
                        Short.MAX_VALUE).addComponent(this.infoPanel));
        this.layout.setVerticalGroup(this.layout
                .createSequentialGroup()
                .addComponent(this.openDirButton)
                .addGroup(
                        this.layout.createParallelGroup()
                                .addComponent(this.parentDirButton)
                                .addComponent(this.loadingLabel)
                                .addComponent(this.currentPathLabel))
                .addComponent(this.scrollPane, 0, GroupLayout.DEFAULT_SIZE,
                        Short.MAX_VALUE)
                .addComponent(this.infoPanel, GroupLayout.PREFERRED_SIZE,
                        GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
    }

    public void setFileLister(FileLister fileLister) {
        if(fileLister == null) {
            throw new IllegalArgumentException("FileLister cannot be null.");
        }
        this.fileLister = fileLister;
    }

    @Override
    public void update(Observable o, Object arg) {
        if(o != null && o.equals(this.fileLister) && arg instanceof List<?>) {
            File currentDir = this.fileLister.getCurrentDir();

            @SuppressWarnings("unchecked")
            List<File> files = (List<File>) arg;

            // Update list of files
            this.fileList.setListData(files.toArray());

            // Update loading label
            this.loadingLabel.setVisible(false);

            // Update current path label
            this.currentPathLabel.setText(currentDir.getAbsolutePath());
            // Set parent button state
            if(currentDir != null && currentDir.getParentFile() != null) {
                this.parentDirButton.setEnabled(currentDir.getParentFile()
                        .isDirectory());
            }
        }
    }
}